package com.ziiwee.reduce.commons.utils;

import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;

public class DateUtil {

    public static long SECOND = 1000;
    public static long MINUTE = SECOND * 60;
    public static long HOUR = MINUTE * 60;
    public static long DAY = HOUR * 24;
    public static long WEEK = DAY * 7;

    public static List<String> DEFAULT_FORMATS = Arrays.asList(
            "yyyy-MM-dd'T'HH:mm:ss.SSSZ",
            "yyyy-MM-dd HH:mm:ss",
            "yyyy-MM-dd",
            "yyyy-MM",
            "yyyy"
    );

    public static String format(Date date) {
        for (String format : DEFAULT_FORMATS) {
            String value = format(date, format);
            if (value != null) {
                return value;
            }
        }
        return null;
    }

    public static Date parse(String date) {
        for (String format : DEFAULT_FORMATS) {
            Date value = parse(date, format);
            if (value != null) {
                return value;
            }
        }
        return null;
    }

    public static String format(Date date, String format) {
        try {
            return new SimpleDateFormat(format).format(date);
        } catch (Exception e) {
            return null;
        }
    }

    public static Date parse(String date, String format) {
        try {
            return new SimpleDateFormat(format).parse(date);
        } catch (Exception e) {
            return null;
        }
    }

    public static Date operate(Date date, Consumer<LocalDateTime> operate) {
        LocalDateTime time = asLocalDateTime(date);
        operate.accept(time);
        return asDate(time);
    }

    public static String operate(String date, String format, Consumer<LocalDateTime> operate) {
        LocalDateTime time = asLocalDateTime(Objects.requireNonNull(parse(date, format)));
        operate.accept(time);
        return format(asDate(time), format);
    }

    public static Date asDate(LocalDate date) {
        return Date.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant());
    }

    public static Date asDate(LocalDateTime dateTime) {
        return Date.from(dateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    public static LocalDate asLocalDate(Date date) {
        return Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDate();
    }

    public static LocalDateTime asLocalDateTime(Date date) {
        return Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDateTime();
    }

}
